﻿/*
 * Cratos Example
 * Cratos Main Form class
 * 
 * Copyright (c) 2011-2012 Draco
 * 
 * This file is part of Cratos.
 * 
 * Cratos is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * Cratos is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Cratos.  If not, see <http://www.gnu.org/licenses/>.
 * 
 *       .==.        .==.
 *      //'^\\      //^'\\
 *     // ^ ^\(\__/)/^ ^^\\
 *    //^ ^^ ^/6  6\ ^^ ^ \\
 *   //^ ^^ ^/( .. )\^ ^ ^ \\
 *  // ^^ ^/\| V""V|/\^ ^ ^ \\
 * //^^/\/ /  '~~'  \ \/\^ ^ \\
 *  ------------------------------------
 *  HERE BE DRAGONS
 *  
 *  Johan Dercksen - johan@draco.co.za
 */
using System;
using System.Text;
using System.Linq;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;

using Cratos.Tools.General;
using Cratos.Example.DataObject;

namespace Cratos.Example
{
	/// <summary>
	/// Main Form class
	/// </summary>
	public partial class MainForm : Form
	{
		#region Class Constant declarations
		#endregion

		#region Class Delegate declarations
		private delegate void SetupPagingControlsCallback();
		private delegate void SetupListViewCallback();
		private delegate void SetupPagingColumnsCallback();
		#endregion

		#region Class Event declarations
		#endregion

		#region Class Variable declarations
		private DOTitlePagingCollection doPagingTitles;
		#endregion

		#region Class Constructors & Destructors
		/// <summary>
		/// Class Constructor
		/// </summary>
		public MainForm()
		{
			// Initialize the relevant component(s)
			InitializeComponent();
		}
		#endregion

		#region Class Properties
		#endregion

		#region Class Methods
		#endregion

		#region Class Support Methods
		private void OnMainFormLoad(object sender, EventArgs e)
		{
			// Declare the required variables

			// Return to calling method
			return;
		}

		private void OnbtnCloseClick(object sender, EventArgs e)
		{
			// Declare the required variables

			// Close the application
			this.Close();

			// Return to calling method
			return;
		}

		private void NewMessage(string newMessage)
		{
			// Declare the required variables
			StringBuilder newListMsg;

			// Clear messages if necessary
			if (this.listMessages.Items.Count > 250) { this.listMessages.Items.Clear(); }

			// Create and Setup the new List message
			newListMsg = new StringBuilder();
			newListMsg.AppendFormat("[{0}] {1}", DateTime.Now, newMessage);

			// Add the message to the list
			this.listMessages.Items.Add(newListMsg.ToString());
			this.listMessages.SelectedItem = this.listMessages.Items[this.listMessages.Items.Count - 1];

			// Hand over to the OS
			Application.DoEvents();

			// Return to calling method
			return;
		}

		private void NewErrorMessage(string errorSource, string errorMessage)
		{
			// Declare the required variables
			StringBuilder newErrorMsg;

			// Clear any current error(s)
			this.txtErrorMessage.Clear();

			// Create and Setup the new List message
			newErrorMsg = new StringBuilder();
			newErrorMsg.AppendLine(string.Format("Date: {0}\nSource: {1}", DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"), 
																																		 errorSource));
			newErrorMsg.AppendLine(string.Format("Error Message:\n{0}", errorMessage));

			// Set the new error
			this.txtErrorMessage.Text = newErrorMsg.ToString();

			// Hand over to the OS
			Application.DoEvents();

			// Return to calling method
			return;
		}

		private void OnBtnFirstPageClick(object sender, EventArgs e)
		{
			// Declare the required variables

			// Make sure we have data to work with
			if (this.doPagingTitles != null) { this.doPagingTitles.FirstPage(); }

			// Update the Paging controls
			this.SetupPagingControls();

			// Update the Listview
			this.SetupListView();

			// Return to calling method
			return;
		}

		private void OnBtnPreviousPageClick(object sender, EventArgs e)
		{
			// Declare the required variables

			// Make sure we have data to work with
			if (this.doPagingTitles != null) { this.doPagingTitles.PreviousPage(); }

			// Update the Paging controls
			this.SetupPagingControls();

			// Update the Listview
			this.SetupListView();

			// Return to calling method
			return;
		}

		private void OnBtnNextPageClick(object sender, EventArgs e)
		{
			// Declare the required variables

			// Make sure we have data to work with
			if (this.doPagingTitles != null) { this.doPagingTitles.NextPage(); }

			// Update the Paging controls
			this.SetupPagingControls();

			// Update the Listview
			this.SetupListView();

			// Return to calling method
			return;
		}

		private void OnBtnLastPageClick(object sender, EventArgs e)
		{
			// Declare the required variables

			// Make sure we have data to work with
			if (this.doPagingTitles != null) { this.doPagingTitles.LastPage(); }

			// Update the Paging controls
			this.SetupPagingControls();

			// Update the Listview
			this.SetupListView();

			// Return to calling method
			return;
		}

		#region Single Example
		private void OnbtnCratosSingleClick(object sender, EventArgs e)
		{
			// Declare the required variables
			DOTitle doTitle;

			// Write a message to the console
			this.NewMessage("Retrieving Single Item");

			// Create and Setup the Title Data Object
			doTitle              = new DOTitle();
			doTitle.Id           = 1;
			doTitle.DBActionType = DOCratosActionType.StoredProcedure;
			doTitle.DOAction     = DOCratosAction.Retrieve;

			// Send the request to the Data Object layer
			if (doTitle.PerformAction())
			{
				this.NewMessage("Successfully retrieved the Title :)");
				this.NewMessage(string.Format("Title is {0}", doTitle.Name));
			}
			else
			{
				this.NewErrorMessage("Cratos Single", doTitle.ErrorMessage);
			}

			// Return to calling method
			return;
		}
		#endregion

		#region Single Embedded Example
		private void OnbtnCratosSingleEmbeddedClick(object sender, EventArgs e)
		{
			// Declare the required variables
			DOPerson doPerson;

			// Write a message to the console
			this.NewMessage("Retrieving Embedded Item");

			// Create and Setup the Title Data Object
			doPerson                = new DOPerson();
			doPerson.Id             = 1;
			doPerson.DOAction       = DOCratosAction.Retrieve;
			doPerson.Title.DOAction = DOCratosAction.Retrieve;

			// Send the request to the Data Object layer
			if (doPerson.PerformAction())
			{
				this.NewMessage(string.Format("Person Title is {0}", doPerson.Title.Name));
			}
			else
			{
				this.NewErrorMessage("Cratos Single Embedded", doPerson.ErrorMessage);
			}

			// Return to calling method
			return;
		}
		#endregion

		#region Collection Example
		private void OnbtnCratosCollectionClick(object sender, EventArgs e)
		{
			// Declare the required variables
			DOTitleCollection doTitles;

			// Write a message to the console
			this.NewMessage("Retrieving Collection");

			// Create and Setup the Title Data Object
			doTitles                         = new DOTitleCollection();
			doTitles.DataObject.DBActionType = DOCratosActionType.StoredProcedure;
			doTitles.CollectionAction        = DOCratosCollectionAction.Retrieve;
			doTitles.MaxRecords						   = 10000;

			// Send the request to the Data Object layer
			if (doTitles.PerformAction())
			{
				this.NewMessage("Successfully retrieved the Titles Collection :)");
				this.NewMessage(string.Format("No of Titles: {0}", doTitles.Count));
				this.NewMessage(string.Format("Result: {0}", doTitles.CollectionActionResult));
			}
			else
			{
				this.NewErrorMessage("Cratos Collection", doTitles.ErrorMessage);
			}

			// Return to calling method
			return;
		}
		#endregion

		#region Collection Paging Example
		private void OnbtnCratosPagingClick(object sender, EventArgs e)
		{
			// Declare the required variables

			// Write a message to the console
			this.NewMessage("Retrieving Paging Collection");

			// Clear all columns
			this.listPagingResults.Columns.Clear();

			// Create and Setup the Title Data Object
			this.doPagingTitles                         = new DOTitlePagingCollection();
			this.doPagingTitles.DataObject.DBActionType = DOCratosActionType.StoredProcedure;
			this.doPagingTitles.CollectionAction        = DOCratosCollectionAction.Retrieve;

			// Update the Paging controls
			this.SetupPagingControls();

			// Subscribe to the relevant event(s)
			this.doPagingTitles.NewPage   += new CollectionNewPageEventHandler(this.OnTitlesNewPage);
			this.doPagingTitles.Error		  += new CollectionErrorEventHandler(this.OnTitlesError);
			this.doPagingTitles.Completed += new CollectionCompletedEventHandler(this.OnTitlesCompleted);

			// Send the request to the Data Object layer
			if (doPagingTitles.PerformAction())
			{
				this.NewMessage("Successfully Submitted a request to load the Title with Paging");
			}
			else
			{
				this.NewErrorMessage("Cratos Paging", this.doPagingTitles.ErrorMessage);
			}

			// Return to calling method
			return;
		}

		private void OnTitlesError(Collection<CratosError> errorCollection)
		{
			// Declare the required variables

			// Display the relevant Error Message
			this.NewErrorMessage("Cratos Paging", this.doPagingTitles.ErrorMessage);

			// Return to calling method
			return;
		}

		private void OnTitlesNewPage(long pageNo, Collection<IDOCratos> doCollection)
		{
			// Declare the required variables

			// Update the Current Page
			if (this.doPagingTitles.CurrentPage <= 0) { this.doPagingTitles.CurrentPage = 1; }

			// Add the relevant columns if required
			if (this.listPagingResults.Columns.Count <= 0) { this.SetupPagingColumns(); }

			// Update the Paging controls
			this.SetupPagingControls();

			// Write a message to the console
			//this.NewMessage(string.Format("Title Page received: {0} Record Count: {1}", pageNo, this.doPagingTitles.RecordCount));

			// Return to calling method
			return;
		}

		private void OnTitlesCompleted(DOCratosActionResult actionResult, Collection<IDOCratos> doCollection)
		{
			// Declare the required variables

			// Update the Paging controls
			this.SetupPagingControls();

			// Write a message to the console
			this.NewMessage("Title with Paging loading completed");

			// Return to calling method
			return;
		}
		#endregion

		private void SetupPagingControls()
		{
			// Declare the required variables
			SetupPagingControlsCallback funcCallback;

			if (this.InvokeRequired) 
			{ 
				// Create, Setup and call the callback action
				funcCallback = new SetupPagingControlsCallback(this.SetupPagingControls);
				this.Invoke(funcCallback, null);
			}
			else
			{
				// Make sure we have data to work with
				if (this.doPagingTitles == null)
				{
					// Update the relevant Textboxes
					this.txtPageNo.Text    = "0";
					this.txtNoOfPages.Text = "0";

					// Update the relevant buttons
					this.btnFirstPage.Enabled    = false;
					this.btnPreviousPage.Enabled = false;
					this.btnNextPage.Enabled     = false;
					this.btnLastPage.Enabled     = false;
				}
				else
				{
					// Update the relevant Textboxes
					this.txtPageNo.Text    = this.doPagingTitles.CurrentPage.ToString();
					this.txtNoOfPages.Text = this.doPagingTitles.PageCount.ToString();

					// Update the relevant buttons
					this.btnFirstPage.Enabled    = ((this.doPagingTitles.PageCount > 0) && (this.doPagingTitles.CurrentPage > 1));
					this.btnPreviousPage.Enabled = ((this.doPagingTitles.PageCount > 0) && (this.doPagingTitles.CurrentPage > 1));
					this.btnNextPage.Enabled     = ((this.doPagingTitles.PageCount > 0) && (this.doPagingTitles.CurrentPage < this.doPagingTitles.PageCount));
					this.btnLastPage.Enabled     = ((this.doPagingTitles.PageCount > 0) && (this.doPagingTitles.CurrentPage < this.doPagingTitles.PageCount));
				}

				// Hand over to OS
				Application.DoEvents();
			}

			// Return to calling method
			return;
		}

		private void SetupListView()
		{
			// Declare the required variables
			ListViewItem					newListItem;
			SetupListViewCallback funcCallback;

			if (this.InvokeRequired) 
			{
				// Create, Setup and call the callback action
				funcCallback = new SetupListViewCallback(this.SetupListView);
				this.Invoke(funcCallback, null);
			}
			else 
			{
				// Clear all current list items
				this.listPagingResults.Items.Clear();

				// Perform the required data binding
				this.listPagingResults.BeginUpdate();
				foreach (IDOCratos currentItem in this.doPagingTitles)
				{
					// Create and Setup the new List Item
					newListItem = new ListViewItem(this.doPagingTitles.DataObject.AllDOProperties[0].GetValue(currentItem, null).ToString());

					// Process the rest of the properties
					for (int loopCount = 1; loopCount < this.doPagingTitles.DataObject.AllDOProperties.Count; loopCount++)
					{
						newListItem.SubItems.Add(this.doPagingTitles.DataObject.AllDOProperties[loopCount].GetValue(currentItem, null).ToString());
					}

					// Add the new Listitem to the Item list
					this.listPagingResults.Items.Add(newListItem);
				}
				this.listPagingResults.EndUpdate();

				// Hand over to OS
				Application.DoEvents();
			}

			// Return to calling method
			return;
		}

		private void SetupPagingColumns()
		{
			// Declare the required variables
			ColumnHeader								newColumn;
			SetupPagingColumnsCallback	funcCallback;

			if (this.InvokeRequired)
			{
				// Create, Setup and call the callback action
				funcCallback = new SetupPagingColumnsCallback(this.SetupPagingColumns);
				this.Invoke(funcCallback, null);
			}
			else
			{
				// Process all the DO Properties
				foreach (PropertyInfo currentProperty in this.doPagingTitles.DataObject.AllDOProperties)
				{
					// Create and Setup the new Column
					newColumn      = new ColumnHeader();
					newColumn.Name = "PagingCol_" + currentProperty.Name;
					newColumn.Text = currentProperty.Name;

					// Add the new column to the list
					this.listPagingResults.Columns.Add(newColumn);
				}

				// Update the Listview
				this.SetupListView();
			}

			// Return to calling method
			return;
		}
		#endregion
	}
}
